/* globals Set */

import electron, { shell } from 'electron';
import path from 'path';
import extName from 'ext-name';
import unusedFilename from 'unused-filename';

const app = electron.app || electron.remote.app;
const optionsCaches = {};
function getFilenameFromMime(name, mime) {
  const exts = extName.mime(mime);
  if (exts.length !== 1) {
    return name;
  }
  return `${name}.${exts[0].ext}`;
}

/**
 * 获取下载目录
 */
const getDownloadsDir = () => {
  try {
    return app.getPath('downloads');
  } catch (error) {
    //
  }
  try {
    return app.getPath('documents');
  } catch (error) {
    //
  }
  try {
    return app.getPath('home');
  } catch (error) {
    //
  }
};

const defOptions = { showBadge: true, showProgressBar: true };
const registerListener = (session, win, send) => {
  const downloadItems = new Set();
  let receivedBytes = 0;
  let completedBytes = 0;
  let totalBytes = 0;
  const activeDownloadItems = () => downloadItems.size;
  const progressDownloadItems = () => receivedBytes / totalBytes;

  const listener = (e, item) => {
    const downloadUrl = item.getURL();
    const options = { ...defOptions, ...optionsCaches[downloadUrl] };
    delete optionsCaches[downloadUrl];
    downloadItems.add(item);
    totalBytes += item.getTotalBytes();

    const dir = options.directory || getDownloadsDir();
    let filePath;
    if (dir) {
      if (options.filename) {
        filePath = path.isAbsolute(options.filename) ? options.filename : path.join(dir, options.filename);
      } else {
        const filename = item.getFilename();
        const name = path.extname(filename) ? filename : getFilenameFromMime(filename, item.getMimeType());
        filePath = unusedFilename.sync(path.join(dir, name));
      }
      if (!options.saveAs) {
        item.setSavePath(filePath);
      }
    }

    send('start', item);

    item.on('updated', () => {
      receivedBytes = [...downloadItems].reduce((receivedBytes, item) => {
        receivedBytes += item.getReceivedBytes();
        return receivedBytes;
      }, completedBytes);

      if (options.showBadge && ['darwin', 'linux'].includes(process.platform)) {
        app.setBadgeCount(activeDownloadItems());
      }

      if (options.showProgressBar && !win.isDestroyed()) {
        win.setProgressBar(progressDownloadItems());
      }
      send('progress', item);
    });

    item.on('done', (e, state) => {
      completedBytes += item.getTotalBytes();
      downloadItems.delete(item);

      if (options.showBadge && ['darwin', 'linux'].includes(process.platform)) {
        app.setBadgeCount(activeDownloadItems());
      }

      if (!win.isDestroyed() && !activeDownloadItems()) {
        win.setProgressBar(-1);
        receivedBytes = 0;
        completedBytes = 0;
        totalBytes = 0;
      }

      if (state === 'cancelled') {
        send('cancelled', item);
      } else if (state === 'interrupted') {
        send('interrupted', item);
      } else if (state === 'completed') {
        if (dir) {
          if (process.platform === 'darwin') {
            app.dock.downloadFinished(filePath);
          }

          if (options.openFolderWhenDone) {
            shell.showItemInFolder(path.join(dir, item.getFilename()));
          }
        }
        send('completed', item);
      }
    });
  };

  session.on('will-download', listener);
};

const downloadItem = item => {
  return {
    getSavePath: item.getSavePath(),
    isPaused: item.isPaused(),
    canResume: item.canResume(),
    getURL: item.getURL(),
    getMimeType: item.getMimeType(),
    getFilename: item.getFilename(),
    getTotalBytes: item.getTotalBytes(),
    getReceivedBytes: item.getReceivedBytes(),
    getContentDisposition: item.getContentDisposition(),
    getState: item.getState(),
    getURLChain: item.getURLChain(),
    getLastModifiedTime: item.getLastModifiedTime(),
    getETag: item.getETag(),
    getStartTime: item.getStartTime(),
  };
};
export default (win, send) => {
  const sendProxy = (action, item) => {
    if (!send) return;
    send('download', action, item && downloadItem(item));
  };
  app.on('session-created', session => {
    registerListener(session, win, sendProxy);
  });
};

export const downloadOptions = (url, options) => {
  if (options && typeof options === 'object') {
    optionsCaches[url] = options;
  }
  return Promise.resolve();
};
